/**
 * phi
 */

var $id = function(id) { return document.getElementById(id); };
var $classes = function(c) { return document.getElementsByClassName(c); };
var $create = function(tag) { return document.createElement(tag); };

if (!HTMLElement.prototype.innerText) {
    HTMLElement.prototype.__defineGetter__("innerText", function(){
        return this.textContent;
    });
    HTMLElement.prototype.__defineSetter__("innerText", function(text){
        this.textContent = text;
    });
}

Array.prototype.clone = function(deep) {
    if (deep == true) {
        var a = Array(this.length);
        for (var i=0; i<this.length; ++i) {
            a[i] = (this[i].clone) ? this[i].clone(deep) : this[i];
        }
        return a;
    };
    
    return Array.apply(null, this);
};

/**
 * 入れ替え
 */
Array.prototype.swap = function(i, j) {
    var temp = this[i];
    this[i] = this[j];
    this[j] = temp;
};









var BASE_X = 20;
var BASE_Y = 420;
var VALUE_MAX_NUM = 360;
var VALUE_LIST_MAX_NUM = 30;

var value_list = Array(VALUE_LIST_MAX_NUM);
window.onload = function()
{
    // リセット
    reset();
    
    var sortButtonList = $classes("sort-button");
    
    for (var i=0; i<sortButtonList.length; ++i) {
        sortButtonList[i].addEventListener("click", function(){
            reset(this.id);
            start(this.id);
        }, false);
    }
};

var reset = function(s)
{
    // ランダムな数値をセットし直す
    for (var i=0; i<VALUE_LIST_MAX_NUM; ++i) {
        value_list[i] = Math.floor( Math.random()*VALUE_MAX_NUM );
    }
    // 描画
    drawBarList();
    
    // ソートのコードをセット
    var sort_name = ((s) ? s:location.hash.substr(1)) + "Sort";
    if (window[sort_name]) {
        var code = window[sort_name].toString();
        // 記録部分を削除
        code = code.replace(/\/\/ 過程を記録\r\n/g, "");
        code = code.replace(/.*sort_process_list.*\r\n/g, "");
        $id("p").innerText = code;
        prettyPrint();
    }
};

/**
 * 開始
 */
var start = function(s)
{
    var sort_name = ((s) ? s:location.hash.substr(1)) + "Sort";
    if (window[sort_name]) sort( window[sort_name] );
};

/**
 * ソート
 */
var sort = function(sort_func)
{
    var start_time = new Date();
    // ソート
    console.time("sort");
    var sort_process_list = sort_func(value_list);
    console.timeEnd("sort");
    
    var canvas = $id("c");
    var context = canvas.getContext("2d");
    var index = 0;
    var id = setInterval(function(){
        var list = sort_process_list[index++];
        // 描画
        context.clearRect(0, 0, 640, 480);
        for (var i=0; i<VALUE_LIST_MAX_NUM; ++i) {
            drawBar(BASE_X+i*20, BASE_Y, list[i], context);
        }
        // 最後まで描画したらインターバルを止める
        if (!sort_process_list[index]) { clearInterval(id); }
    }, 5);
}

/**
 * バブルソート
 */
var bubbleSort = function(list)
{
    var sort_process_list = [];
    var len = list.length;
    
    for (var i=0; i<len-1; ++i) {
        for (var j=len-1; j>i; --j) {
            // 交換
            if (list[j] < list[j-1]) {
                list.swap(j, j-1);
                // 過程を記録
                sort_process_list.push(list.clone());
            }
        }
    }
    
    return sort_process_list;
};

var bidirectionalBubbleSort = function(list)
{
    var sort_process_list = [];
        
    var start   = -1;
    var end     = list.length;
    var flag = 0;
    
    while (start<end) {
        ++start;
        --end;
        
        flag = 0; 
        for (var i=start; i<end; ++i) {
            if (list[i] > list[i+1]) {
                list.swap(i, i+1);
                flag |= 1;
            }
            // 過程を記録
            sort_process_list.push(list.clone());
        }
        if (!flag) break;
        
        flag = 0; 
        for (var i=end; i>=start; --i) {
            if (list[i] > list[i+1]) {
                list.swap(i, i+1);
                flag |= 1;
            }
            // 過程を記録
            sort_process_list.push(list.clone());
        }
        if (!flag) break;
    };
    
    return sort_process_list;
};

var selectionSort = function(list)
{
    var sort_process_list = [];
    
    for (var i=0; i<VALUE_LIST_MAX_NUM-1; ++i) {
        for (var j=i+1; j<VALUE_LIST_MAX_NUM; ++j) {
            if (list[j]<list[i]) { list.swap(i, j); }
            // 過程を記録
            sort_process_list.push(list.clone());
        }
    }
    
    return sort_process_list;
};

var quickSort = function(list)
{
    var sort_process_list = [];
    
    (function(start, end) {
        var key = list[ Math.floor((start+end)/2) ];
        var i = start;
        var j = end;
        while (true) {
            while (list[i]<key) ++i;
            while (key<list[j]) --j;
            if (i>=j) break;
            list.swap(i, j);
            ++i;
            --j;
            // 過程を記録
            sort_process_list.push(list.clone());
        }
        
        // 再帰呼び出し
        if (start < i-1) arguments.callee(start, i-1);
        if (j+1 < end)   arguments.callee(j+1, end);
    })(0, list.length-1);
    
    return sort_process_list;
};

var drawBar = function(x, y, value, context)
{
    var rect = [
        x,
        y-value,
        10,
        value
    ];
    context.fillStyle = "hsla(" + value + ", 100%, 50%, 1.0)"
    context.fillRect(rect[0],rect[1],rect[2],rect[3]);
};

var drawBarList = function()
{
    var canvas = $id("c");
    var context = canvas.getContext("2d");
    context.clearRect(0, 0, 640, 480);
    
    for (var i=0; i<VALUE_LIST_MAX_NUM; ++i) {
        drawBar(BASE_X+i*20, BASE_Y, value_list[i], context);
    }
};

